//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
//==========================================================================
// Copyright (c) 2000-2004,  Elastos, Inc.  All Rights Reserved.
//**author:hanxu
//**y/m/d:2005/5/16
//==========================================================================

#include <bsp.h>
#include <init.h>
#include <regs.h>

#include "timer.h"

uint32_t    PIT_ClockRate;          // unit: HZ
uint32_t    PIT_ClockCycle;         // unit: NS

#define PIT_LATCH   \
    ((uint32_t)((PIT_ClockRate + krn.uTickRate / 2) / krn.uTickRate))

#define RTC_PORT(x)	(0x70 + (x))
#define abs(x) ((x)>0?(x):(-x))

static inline unsigned char p6032_inb(unsigned long port)
{
	return *(volatile unsigned char *)(0xbfd00000+ port);
}

#define p6032_outb(val,port)							\
do {									\
	*(volatile unsigned char *)(0xbfd00000 + port) = val;	\
} while(0)


static unsigned char p6032_rtc_read_data(unsigned char addr)
{
	p6032_outb(addr, 0x70);
	return p6032_inb(0x71);
}

static void p6032_rtc_write_data(unsigned char data, unsigned char addr)
{
	p6032_outb(addr, 0x70);
	p6032_outb(data, 0x71);
}

static unsigned long cal_r4koff(void)
{
	unsigned long lCount;
	unsigned int uFlags;

	read_cp0_register($12, uFlags);
	write_cp0_register($12, uFlags & (~0x00000001));

	/* Start counter exactly on falling edge of update flag */
	while (p6032_rtc_read_data(10) & 0x80);
	while (!(p6032_rtc_read_data(10) & 0x80));

	/* Start r4k counter. */
	write_cp0_register($9, 0);

	/* Read counter exactly on falling edge of update flag */
	while (p6032_rtc_read_data(10) & 0x80);
	while (!(p6032_rtc_read_data(10) & 0x80));

	read_cp0_register($9,lCount);

		/* restore interrupts */
	if (uFlags & 0x1) {
	    read_cp0_register($12, uFlags);
	    uFlags |= 0x1;
		write_cp0_register($12, uFlags);
	}

	return (lCount);
}

static void  p6032_time_init(void)
{
    unsigned int    uFreq;

	kprintf("calculating r4koff... ");
	uFreq = cal_r4koff();

    uFreq += 500;    /* round */

    uFreq -= uFreq%1000;

    PIT_ClockRate = uFreq;

    PIT_ClockCycle = (1000000000 / PIT_ClockRate);

    uFreq = 2 * uFreq;

    kprintf("CPU frequency %d.%02d MHz\n", uFreq/1000000,

                                             (uFreq%1000000)*100/1000000);
}


EXTERN_C DECL_CODEINIT void CDECL InitPIT()
{
        //p6032_rtc_init
        kprintf("entering InitPIT......\n");

    	p6032_rtc_write_data((0x04 | 0x02 | 0x08), 11);

        //p6032_time_init
    	p6032_time_init();

    	return;
}

EXTERN_C uint_t CDECL BspGetPITTime()
{
    return 0;
}

EXTERN_C void CDECL BspReloadPIT()
{
    uint32_t    uPitCount;
    
    uPitCount = PitRead();
    uPitCount += PIT_LATCH;
    PitWrite(uPitCount);    
}

